package com.luban.springcloud.ribbon;

import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public class MyRibbonRule extends AbstractLoadBalancerRule {

    private AtomicInteger nextServerCyclicCounter;

    private Random rand;

    @Autowired
    DiscoveryClient discoveryClient;

    @Autowired
    private SpringClientFactory clientFactory;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    public MyRibbonRule() {
        nextServerCyclicCounter = new AtomicInteger(0);
        rand = new Random();
    }

    @Override
    public Server choose(Object key) {

        ILoadBalancer lb = getLoadBalancer();
        EurekaServerExtractor eurekaServerExtractor = new EurekaServerExtractor(clientFactory);

        List<Server> servers = lb.getReachableServers();

        //存储所有的灰度实例的列表
        List<Server> grayServerList = new ArrayList<>();
        List<Server> normalServerList = new ArrayList<>();
        double weight = 0;

        servers.forEach(server -> {
            Map<String, String> serverMetadata = eurekaServerExtractor.getServerMetadata(server);

            if("true".equals(serverMetadata.get("gray"))){
                grayServerList.add(server);
            } else {
                normalServerList.add(server);
            }
        });

        //如果有灰度实例，那么按照灰度实例权重进行路由
        if(grayServerList.size() > 0) {
            String var = eurekaServerExtractor.getServerMetadata(grayServerList.get(0)).get("weight");
            if (var == null) {
                weight = 0;
            } else {
                weight = Double.parseDouble(var);
            }

            int i = rand.nextInt(100);
            if(i <= weight * 100) {
                int grayIndex = rand.nextInt(grayServerList.size());
                return grayServerList.get(grayIndex);
            } else {
                int Index = rand.nextInt(normalServerList.size());
                return normalServerList.get(Index);
            }
        } else {
            //如果没有灰度实例，那么进行轮询路由
            int nextServerIndex = incrementAndGetModulo(servers.size());
            Server server = servers.get(nextServerIndex);
            if (server == null) {
                Thread.yield();
            }

            assert server != null;
            if (server.isAlive() && (server.isReadyToServe())) {
                return (server);
            }
            return server;
        }
    }

    private int incrementAndGetModulo(int modulo) {
        for (;;) {
            int current = nextServerCyclicCounter.get();
            int next = (current + 1) % modulo;
            if (nextServerCyclicCounter.compareAndSet(current, next)) {
                return next;
            }
        }
    }
}
